import { Transformer } from 'markmap-lib';
import { Markmap } from 'markmap-view';
import cssStr from './style.css?inline';

const render_failed_msg = '😞 Failed to render the mind map'
const data_empty_msg = '😞 Data is empty'

const delayUpdate = (fn: () => void, wait = 0) => setTimeout(fn, wait);

/**
 * 思维导图Web组件类
 * 支持通过content属性传入Markdown内容来渲染思维导图
 */
class UiMarkmap extends HTMLElement {
    private container: HTMLElement | null = null;
    private loadingEl: HTMLElement | null = null;
    private emptyEl: HTMLElement | null = null;
    private svgEl: SVGSVGElement | null = null;
    private markmap: Markmap | null = null;
    private resizeObserver: ResizeObserver | null = null;

    constructor() {
        super();
        this.attachShadow({ mode: 'open' });
    }

    /**
     * 定义需要观察的属性
     * @returns {string[]} 观察的属性列表
     */
    static get observedAttributes() {
        return ['content', 'aspect-ratio'];
    }

    /**
     * 属性变化回调函数
     * @param {string} name 属性名
     * @param {string | null} oldValue 旧值
     * @param {string | null} newValue 新值
     */
    attributeChangedCallback(name: string, oldValue: string | null, newValue: string | null) {
        if (oldValue !== newValue) {
            switch (name) {
                case 'content':
                    this.renderMarkmap();
                    break;
                case 'aspect-ratio':
                    this.updateContainerStyle();
                    break;

                default:
                    break;
            }
        }
    }

    /**
     * 组件连接到DOM时的回调
     */
    connectedCallback() {
        this.render();
        this.renderMarkmap();
    }

    /**
     * 组件从DOM断开时的回调
     */
    disconnectedCallback() {
        this.resizeObserver?.disconnect();
    }

    get aspectRatio() {
        return this.getAttribute('aspect-ratio');
    }
    set aspectRatio(value) {
        if (value) {
            this.setAttribute('aspect-ratio', value);
        }
    }

    get content() {
        return this.getAttribute('content');
    }
    set content(value) {
        if (value) {
            this.setAttribute('content', value);
        }
    }

    /**
     * 渲染组件的基础结构
     */
    render() {
        if (!this.shadowRoot) {
            return
        }
        const inlineStyle = [
            this.aspectRatio
                ? `aspect-ratio:${this.aspectRatio}`
                : null
        ].filter(Boolean).join(';');
        this.shadowRoot.innerHTML = `
        <style>${cssStr}</style>
        <div class="ui-markmap" ${inlineStyle ? `style="${inlineStyle}"` : ''}>
            <svg class="ui-markmap-svg"></svg>
            <div class="ui-markmap-loading">
                <div class="loading"></div>
            </div>
            <div class="ui-markmap-empty ui-hide">${render_failed_msg}</div>
        </div>
        `;
        this.container = this.shadowRoot.querySelector('.ui-markmap');
        this.svgEl = this.shadowRoot.querySelector('.ui-markmap-svg');
        this.loadingEl = this.shadowRoot.querySelector('.ui-markmap-loading');
        this.emptyEl = this.shadowRoot.querySelector('.ui-markmap-empty');
    }

    toggleLoading(isShow = true) {
        if (isShow) {
            this.loadingEl?.classList.remove('ui-hide');
        } else {
            this.loadingEl?.classList.add('ui-hide');
        }
    }
    toggleEmpty(isShow = true) {
        if (isShow) {
            this.emptyEl?.classList.remove('ui-hide');
        } else {
            this.emptyEl?.classList.add('ui-hide');
        }
    }

    /**
     * 更新组件尺寸
     */
    updateContainerStyle() {
        if (this.container) {
            if (this.aspectRatio) {
                this.container.style.aspectRatio = this.aspectRatio;
                // 触发思维导图重新适应尺寸
                delayUpdate(() => this.setFit(), 100);
            }
        }
    }

    createMarkmap() {
        if (!this.markmap) {
            const markmapConfig = {
                duration: 300,
                nodeMinHeight: 16,
                spacingVertical: 5,
                spacingHorizontal: 80,
                autoFit: false,
                paddingX: 8,
            }
            this.markmap = Markmap.create(this.svgEl, markmapConfig);
        }
    }

    /**
     * 渲染思维导图
     */
    async renderMarkmap() {
        if (!this.content || !this.container) {
            this.toggleLoading(false);
            this.toggleEmpty(true);
            if (this.emptyEl) {
                this.emptyEl.innerHTML = data_empty_msg;
            }
            return;
        }
        try {
            this.createMarkmap();
            // 初始化转换器和markmap
            const transformer = new Transformer();
            // 转换内容为思维导图数据
            const { root } = transformer.transform(this.content);
            // 更新思维导图
            this.markmap!.setData(root);
            // 设置尺寸观察器
            this.setupResizeObserver();
            // 设置链接点击事件
            this.setupLinkClickHandler();
            this.toggleLoading(false);
            this.toggleEmpty(false);
        } catch (error) {
            console.error('Render Failed:', error);
            this.toggleLoading(false);
            this.toggleEmpty(true);
            if (this.emptyEl) {
                this.emptyEl.innerHTML = render_failed_msg;
            }
        }
    }

    /**
     * 设置尺寸变化观察器
     */
    setupResizeObserver() {
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
        }

        this.resizeObserver = new ResizeObserver(() => {
            this.setFit();
        });

        if (this.svgEl) {
            this.resizeObserver.observe(this.svgEl);
        }
    }

    /**
     * 设置链接点击处理器
     */
    setupLinkClickHandler() {
        setTimeout(() => {
            this.container?.addEventListener('click', (e: MouseEvent) => {
                let a = e.target as HTMLElement | null;
                while (a && a.tagName !== 'A') {
                    a = a.parentElement;
                }
                if (a && a instanceof HTMLAnchorElement) {
                    e.preventDefault();
                    e.stopPropagation();
                    window.open(a.href, '_blank');
                }
            });
        }, 1000);
    }

    /**
     * 公共方法：适应容器尺寸
     */
    setFit() {
        this.markmap?.fit?.();
    }
}

// 注册组件
if (window.customElements.get('ui-markmap') === undefined) {
    customElements.define('ui-markmap', UiMarkmap);
}
